package com.niit.mall.mall.auth.utils;

import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTValidator;
import cn.hutool.jwt.signers.JWTSigner;
import cn.hutool.jwt.signers.JWTSignerUtil;
import com.niit.mall.common.api.ResultCode;
import com.niit.mall.common.exception.Asserts;
import org.springframework.stereotype.Component;

import java.security.KeyPair;
import java.time.Duration;
import java.util.Date;

/**
 * JSON Web Token（JWT）工具类，用于创建和解析访问令牌。
 *
 * @author ChuXuan
 * @date 2025/06/04
 */

@Component
public class JwtTool {
	private final JWTSigner jwtSigner;
	
	public JwtTool(KeyPair keyPair) {
		this.jwtSigner = JWTSignerUtil.createSigner("rs256", keyPair);
	}
	
	/**
	 * 创建 access-token
	 *
	 * @param userId 用户信息
	 * @return access-token
	 */
	public String createToken(Long userId, Duration ttl) {
		// 1.生成jws
		return JWT.create()
				       .setPayload("user", userId)
				       .setExpiresAt(new Date(System.currentTimeMillis() + ttl.toMillis()))
				       .setSigner(jwtSigner)
				       .sign();
	}
	
	/**
	 * 解析token
	 *
	 * @param token token
	 * @return 解析刷新token得到的用户信息
	 */
	public Long parseToken(String token) {
		// 1.校验token是否为空
		if (token == null) {
			Asserts.fail(ResultCode.UNAUTHORIZED);
		}
		
		JWT jwt = null;
		// 2.校验并解析jwt
		try {
			jwt = JWT.of(token).setSigner(jwtSigner);
		} catch (Exception e) {
			Asserts.fail(ResultCode.UNAUTHORIZED);
		}
		
		// 确保jwt不为空
		if (jwt == null) {
			Asserts.fail(ResultCode.UNAUTHORIZED);
		}
		
		// 2.校验jwt是否有效
		if (!jwt.verify()) {
			// 验证失败
			Asserts.fail(ResultCode.UNAUTHORIZED);
		}
		// 3.校验是否过期
		try {
			JWTValidator.of(jwt).validateDate();
		} catch (ValidateException e) {
			Asserts.fail(ResultCode.UNAUTHORIZED);
		}
		// 4.数据格式校验
		Object userPayload = jwt.getPayload("user");
		if (userPayload == null) {
			// 数据为空
			Asserts.fail(ResultCode.UNAUTHORIZED);
		}
		
		// 5.数据解析
		try {
			return Long.valueOf(userPayload.toString());
		} catch (RuntimeException e) {
			// 数据格式有误
			Asserts.fail(ResultCode.UNAUTHORIZED);
		}
		
		// 理论上不会执行到这里，因为所有错误情况都会抛出异常
		Asserts.fail(ResultCode.UNAUTHORIZED);
		return null;
	}
}

